<template>
  <div class="tips-search-input" @click.stop>
    <jm-input ref="input" type="text" v-model="keyword" clearable placeholder="请搜索" @input="getCurTips"
      @focus="getCurTips" />

    <!-- 字段 -->
    <div class="fields-list" ref="fields-list" v-if="curTips === 'field' && fieldsList.length > 0">
      <div v-for="(item, index) in fieldsList" :key="index"
        :class="[{ active: curIndex === index }, { tips: item.tips }]" class="fields-item" @click="fieldClick(item)"
        @mousemove="mousemove(index)">
        <span>{{ item.field }}</span>
        <span>{{ item.fieldMeaning ? `（${item.fieldMeaning}）` : '' }}</span>
      </div>
    </div>
    <!-- 操作符 -->
    <div class="operators-list" v-else-if="curTips === 'operator' && operatorsList.length > 0">
      <div v-for="(item, index) in operatorsList" :key="index" class="operators-item"
        :class="[{ active: curIndex === index }, { tips: item.tips }]" @click="operatorClick(item)"
        @mousemove="mousemove(index)">
        <span>{{ item.symbol }}</span>
        <span>{{ item.description ? `（${item.description}）` : '' }}</span>
      </div>
    </div>
    <!-- 连接符 -->
    <div class="connects-list" v-else-if="curTips === 'connect' && connectsList.length > 0">
      <div v-for="(item, index) in connectsList" :key="index" class="connects-item"
        :class="{ active: curIndex === index }" @click="connectClick(item)" @mousemove="mousemove(index)">
        <span>{{ item.key }}</span>
        <span>{{ item.value ? `（${item.value}）` : '' }}</span>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, nextTick, computed, onBeforeUnmount, watch } from 'vue'
import { operatorTypeAll } from './advanced-search'
import { getTabAPI, getDict, getOperators, getSearchFields, getTips } from '@/api/search/index'
import { HttpCodeEnum } from '@packages/share/enums'

const props = defineProps({
  active: { type: String, required: true },
  FieldsList: { type: Array, default: () => [] }
})
const active = computed(() => props.active)

const keyword = ref('')
const input = ref()
const basisOperatorsList: any = ref([]) //获取operators字段
const basisFieldsList: any = ref([]) //获取Fields操作符
const connectsList: any = ref([]) //获取拼接

const curTips = ref('')
const operatorType = ref('')
const tipsList = ref([])
const curIndex = ref(-1)

const getCurTips = () => {
  if (keyword.value === undefined) keyword.value = ''
  if (keyword.value.endsWith('  ')) return
  const index = getIndex()
  let value = ignoreparentheses(keyword.value.slice(index))
  if (!value.trim()) {
    return (curTips.value = 'field')
  }
  const symbols = operatorTypeAll.filter((it) => it.needValue).map((it) => it.symbol)
  if (value.endsWith(' ')) {
    if (symbols.some((it) => value.endsWith(it + ' '))) {
      curTips.value = ''
    } else {
      curTips.value = 'connect'
    }
  } else {
    const curField = basisFieldsList.value.find((it: any) => it.field === value)
    const curOperators = basisOperatorsList.value.find(
      (it: any) => it.operatorType === curField?.fieldType
    )
    operatorType.value = curOperators?.operatorType || ''
    if (operatorType.value) {
      curTips.value = 'operator'
    } else {
      const tip = tipsList.value.find((it: any) => it.field === value)
      if (tip) {
        curTips.value = ''
      } else {
        curTips.value = 'field'
      }
    }
  }
}

const fieldClick = (item: any) => {
  setField(item)
  operatorType.value = ''
  getCurTips()
  setCursorLocation()
}

const setField = (item: any) => {
  const index = getIndex()
  let value = keyword.value.slice(0, index)
  let str = keyword.value.slice(index)
  if (isParentheses(str)) {
    keyword.value = value + '(' + item.field + keyword.value.slice(findEndIndex())
  } else {
    if (str.endsWith(')')) {
      keyword.value = value + item.field + keyword.value.slice(findEndIndex())
    } else {
      keyword.value = value + item.field
    }
  }
}
const findEndIndex = () => {
  let index = keyword.value.length - 1
  for (let i = keyword.value.length - 1; i > 0; i--) {
    if (keyword.value.charAt(i) === ')') {
      index = i
    } else {
      break
    }
  }
  return index
}
const isParentheses = (str: string) => {
  return str.startsWith('(') && str.endsWith(')')
}

const operatorClick = (item: any) => {
  item.tips ? setField(item) : setOperator(item)
  getCurTips()
  setCursorLocation()
}

const setOperator = (item: any) => {
  const index = getIndex()
  let str = keyword.value.slice(index)
  if (isParentheses(str)) {
    keyword.value =
      keyword.value.slice(0, findEndIndex()) +
      ' ' +
      item.symbol +
      ' ' +
      (item.needValue ? '""' : '') +
      keyword.value.slice(findEndIndex())
  } else {
    if (str.endsWith(')')) {
      keyword.value =
        keyword.value.slice(0, findEndIndex()) +
        ' ' +
        item.symbol +
        ' ' +
        (item.needValue ? '""' : '') +
        keyword.value.slice(findEndIndex())
    } else {
      keyword.value += ' ' + item.symbol + ' ' + (item.needValue ? '""' : '')
    }
  }
}

const fieldsList = computed(() => {
  if (curTips.value !== 'field') return []
  const index = getIndex()
  const value = ignoreparentheses(keyword.value.slice(index))
  if (value.trim()) {
    return basisFieldsList.value
      .concat(tipsList.value)
      .filter((item: any) => item.field.includes(value.trim()))
  }
  return basisFieldsList.value
})

const operatorsList = computed(() => {
  if (curTips.value !== 'operator' || !operatorType.value) return []
  const operatorsItem = basisOperatorsList.value.find(
    (operators: any) => operators.operatorType === operatorType.value
  )
  if (!operatorsItem) return []
  const index = getIndex()
  //搜索框现在存在的属性
  const value = ignoreparentheses(keyword.value.slice(index))
  let tips: any = []
  if (value.trim()) {
    //tipsList数组里面filed里面是否有跟value（去掉空格）一样的值 
    tips = tipsList.value.filter((item: any) => item.field.includes(value.trim()))
  }
  let operators = operatorsItem?.operators || []
  // 字段类型为String fieldName属性不以.keyword结尾时，需要过滤掉 等于和不等于，只保留存在
  if (operatorType.value === 'String') {
    //去basisFieldsList里面找filed里面找第一个value一样的值
    const item = basisFieldsList.value.find((item: any) => item.field === value)
    if (!item.fieldName.endsWith('.keyword'))
      operators = operators.filter((item: any) => !item.needValue)
  }
  return operators.concat(tips)
})

const visible = computed(() => {
  if (curTips.value === 'field' && fieldsList.value.length > 0) return true
  if (curTips.value === 'operator' && operatorsList.value.length > 0) return true
  if (curTips.value === 'connect' && connectsList.value.length > 0) return true
  return false
})

const setCursorLocation = () => {
  const index = getIndex()
  // 搜索label
  let str = keyword.value.slice(index)
  let location = keyword.value.length
  if (ignoreparentheses(str).endsWith('""')) {
    const indx = str.indexOf('""', -1)
    if (indx > 0) {
      location = indx + 1 + index
    }
  } else if (str.endsWith(')')) {
    location = findEndIndex()
  }
  nextTick(() => {
    const inputValue = input.value.$refs.input
    if (inputValue) {
      inputValue.focus()
      inputValue.setSelectionRange(location, location)
    }
  })
}

const ignoreparentheses = (value: string) => {
  return value.replace(/\(|\)/g, '')
}
const isRegion = (str: string) => {
  const regionField = ['country', 'province', 'city']
  return regionField.some((field) => str.includes(field))
}
const getIndex = () => {
  let index = -1
  for (const item of [' || ', ' && ']) {
    if (index < keyword.value.lastIndexOf(item)) {
      index = keyword.value.lastIndexOf(item)
    }
  }
  return index === -1 ? 0 : index + 4
}

//获取Fields操作符
const getfields = () => {
  if (props.FieldsList.length > 0) {
    basisFieldsList.value = props.FieldsList
    return
  }
  getTabAPI(props.active).then((res) => {
    let { code, rows } = res.data
    if (code === HttpCodeEnum.SUCCESS) {
      basisFieldsList.value = rows;
    }
  })
}
//获取operators字段
const getoperators = () => {
  getOperators().then((res) => {
    basisOperatorsList.value = res.data.rows || []
  })
}
const getConnects = () => {
  getDict().then((res) => {
    connectsList.value = res.data.rows || []
  })
}
// 获取搜索提示
const getTipsList = () => {
  getTips().then((res) => {
    tipsList.value =
      res.data.rows.map((item: any) => ({
        tips: true,
        field: item.tip.replace(/\s+/g, ' '),
        fieldMeaning: '',
        symbol: item.tip.replace(/\s+/g, ' '),
        description: ''
      })) || []
  })
}
const connectClick = (item: any) => {
  const index = getIndex()
  let str = keyword.value.slice(index)
  if (isParentheses(str)) {
    keyword.value =
      keyword.value.slice(0, findEndIndex()) + item.key + ' ' + keyword.value.slice(findEndIndex())
  } else {
    if (str.endsWith(')')) {
      keyword.value =
        keyword.value.slice(0, findEndIndex()) +
        item.key +
        ' ' +
        keyword.value.slice(findEndIndex())
    } else {
      keyword.value += item.key + ' '
    }
  }
  getCurTips()
  setCursorLocation()
}

const mousemove = (index: number) => {
  curIndex.value = index
}
const blurInput = () => {
  curTips.value = ''
}
const keyup = (e) => {
  // if (!visible.value) return
  // const { list, method } = getInfo()
  // switch (e.keyCode) {
  //   case 13:
  //     if (curIndex.value > -1 && method) {
  //       this.$refs.input.blur()
  //       // this[method](list[curIndex.value])
  //     }
  //     break
  //   case 38:
  //     if (curIndex.value >= 0) curIndex.value--
  //     setScrollLocation()
  //     e.preventDefault()
  //     break
  //   case 40:
  //     if (curIndex.value < list.length - 1) curIndex.value++
  //     setScrollLocation()
  //     e.preventDefault()
  //     break
  //   default:
  //     break
  // }
}

//  setScrollLocation() {
//       if (this.$refs["fields-list"]) {
//         const containter = this.$refs["fields-list"];
//         const top = containter.scrollTop;
//         const containterHeight = containter.clientHeight;
//         const item = containter.querySelector(".fields-item");
//         const itemHeight = item.clientHeight;
//         if (top + containterHeight < (this.curIndex + 1) * itemHeight) {
//           this.$refs["fields-list"].scrollTop += itemHeight;
//         } else if (top > this.curIndex * itemHeight) {
//           this.$refs["fields-list"].scrollTop -= itemHeight;
//         }
//       }
//     },

const getInfo = () => {
  switch (curTips.value) {
    case 'field':
      return { list: fieldsList.value, method: 'fieldClick' }
    case 'operator':
      return { list: operatorsList.value, method: 'operatorClick' }
    case 'connect':
      return { list: connectsList.value, method: 'connectClick' }
    default:
      return { list: [], method: '' }
  }
}
watch(active, () => {
  getfields()
})
onMounted(() => {
  getfields()
  getoperators()
  getTipsList()
  getConnects()
  window.addEventListener('click', blurInput)
  window.addEventListener('keyup', keyup)
})
onBeforeUnmount(() => {
  window.removeEventListener('click', blurInput)
  window.removeEventListener('keyup', keyup)
})

defineExpose({
  keyword
})
</script>

<style lang="scss" scoped>
.tips-search-input {
  position: relative;

  :deep(.el-input) {
    height: 100%;

    .el-input__inner {
      height: 100%;
      font-weight: 400;
      font-size: 16px;
      background-color: #fff;
      border: 0;
      transition: border 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
    }
  }

  .fields-list,
  .operators-list,
  .connects-list {
    position: absolute;
    top: 50px;
    left: 0;
    z-index: 10;
    width: 100%;
    max-height: 300px;
    overflow: auto;
    // color: #021a56;
    color: #007bff;

    background-color: #ffffff;

    &::-webkit-scrollbar {
      width: 8px;
      height: 8px;
    }

    .fields-item,
    .operators-item,
    .connects-item {
      padding: 0 15px;
      line-height: 30px;
      text-align: left;
      cursor: pointer;

      &.tips {
        color: #e2d3d3;
      }
    }
  }
}
</style>
